#ifndef __FS_H__
#define __FS_H__

/*********************************************************************
 * INCLUDES
 */

#include "salcfg.h"

#if (SAL_FS_PRODUCER == _FS_FAT32_)
#include "fatfs.h"
#elif (SAL_FS_PRODUCER == _FS_LINUX_)
#include <dirent.h>
#else
#endif

#ifdef __cplusplus
extern "C" {
#endif

#if (SAL_FS == _ENABLE)

/*********************************************************************
 *  EXTERNAL VARIABLES
 */


/*********************************************************************
 * MACROS
 */

#define F_RDONLY         0x00       //只读打开
#define F_WRONLY         0x01       //只写打开
#define F_RDWR           0x02       //读、写打开
#define F_CREAT          0x40       //若此文件不存在，则创建它。使用时，需要第三个参数
#define F_EXCL           0x80       //如果同时指定了O_CREAT,而文件已经存在，则会出错。
                                    //用此可以测试一个文件是否存在，如果不存在，则创建此文件，
                                    //这使测试和创建者两者成为一个原子操作。
#define F_NOCTTY         0x100      //如果pathname指的终端设备，则不将该设备分配作为此进程的控制终端。
#define F_TRUNC          0x200      //如果此文件存在，而且为只写或读写成功打开，则将其长度截短为0。
#define F_APPEND         0x400      //每次写时都追加到文件的尾端
#define F_NONBLOCK       0x800      //如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件，
                                    //则此选项为文件的本次操作和后续的I/O操作设置非阻塞模式。
#define F_NDELAY         F_NONBLOCK
#define F_SYNC           0x101000   //使每次write都等到物理I/O操作完成，包括由write操作引起的文件属性更新所需的I/O。
#define F_FSYNC          F_SYNC
#define F_ASYNC          0x2000

/*********************************************************************
 * TYPES
 */

/* File function return code (FRESULT) */
typedef enum 
{
    FS_OK = 0,                      /* (0) Succeeded */
    FS_DISK_ERR     = -1,           /* (1) A hard error occurred in the low level disk I/O layer */
    FS_INT_ERR      = -2,           /* (2) Assertion failed */
    FS_NOT_READY    = -3,           /* (3) The physical drive cannot work */
    FS_NO_FILE      = -4,           /* (4) Could not find the file */
    FS_NO_PATH      = -5,           /* (5) Could not find the path */
    FS_INVALID_NAME = -6,           /* (6) The path name format is invalid */
    FS_DENIED       = -7,           /* (7) Access denied due to prohibited access or directory full */
    FS_EXIST        = -8,           /* (8) Access denied due to prohibited access */
    FS_INVALID_OBJECT   = -9,       /* (9) The file/directory object is invalid */
    FS_WRITE_PROTECTED  = -10,      /* (10) The physical drive is write protected */
    FS_INVALID_DRIVE    = -11,      /* (11) The logical drive number is invalid */
    FS_NOT_ENABLED      = -12,      /* (12) The volume has no work area */
    FS_NO_FILESYSTEM    = -13,      /* (13) There is no valid FAT volume */
    FS_MKFS_ABORTED     = -14,      /* (14) The f_mkfs() aborted due to any problem */
    FS_TIMEOUT          = -15,      /* (15) Could not get a grant to access the volume within defined period */
    FS_LOCKED           = -16,      /* (16) The operation is rejected according to the file sharing policy */
    FS_NOT_ENOUGH_CORE  = -17,      /* (17) LFN working buffer could not be allocated */
    FS_TOO_MANY_OPEN_FILES  = -18,  /* (18) Number of open files > _FS_LOCK */
    FS_INVALID_PARAMETER    = -19,  /* (19) Given parameter is invalid */
    FS_OPEN_ERR             = -20,
    FS_READ_ERR             = -21,
    FS_WRITE_ERR            = -22,
    FS_OTHER_ERR            = -23,
} FRESULT_E;

#if (SAL_FS_PRODUCER == _FS_LINUX_)
typedef uint32_t    fd_t;
typedef DIR FSDIR_S;
#elif (SAL_FS_PRODUCER == _FS_FAT32_)
typedef FIL         fd_t;
typedef DIR FSDIR_S;
#else
typedef void FSDIR_S;
#endif

typedef enum
{
    SEEK_HEAD = 0,      //文件开头
    SEEK_NOW  = 1,      //文件偏移指针当前位置
    SEEK_TAIL = 2,      //文件结尾
} SEEK_POS_E;

/* File information structure */
typedef struct 
{
    uint32_t uiFileSize;        /* File size */
    char     acFileName[64];    /* Short file name (8.3 format) */
} FILE_INFO_S;

typedef struct _fs_base
{
    FRESULT_E (*pfFSOpen)(fd_t *phFile, const char* pcPath, uint8_t ucMode);
    FRESULT_E (*pfFSClose)(fd_t *phFile);
    int32_t   (*pfFSRead)(fd_t *phFile, void *pBuff, uint32_t uiSize);
    int32_t   (*pfFSReadLine)(fd_t *phFile, void *pBuff, uint32_t uiSize);
    int32_t   (*pfFSWrite)(fd_t *phFile, const void *pBuff, uint32_t uiSize);
    FRESULT_E (*pfFSSeek)(fd_t *phFile, int32_t iOffset, uint8_t ucWhence);
    FRESULT_E (*pfFSDelete)(const char *pName);
    FRESULT_E (*pfFSGetSize)(fd_t *phFile, uint32_t *puiSize);
    FRESULT_E (*pfFSFlush)(fd_t *phFile);
    FRESULT_E (*pfFSRename)(const char *pOldPath, const char *pNewPath);
    FRESULT_E (*pfFSMkDir)(const char *pPath);
    FRESULT_E (*pfFSDirOpen)(const char *pcDirPath, FSDIR_S *pstDir);
    FRESULT_E (*pfFSDirClose)(FSDIR_S *pstDir);
    FRESULT_E (*pfFSDirRead)(FSDIR_S *pstDir, FILE_INFO_S *pstFileInfo);
    char *    (*pfFSGetCwd)(char *pBuf, uint32_t uiSize);
    FRESULT_E (*pfFSChDir)(const char *pPath);
    FRESULT_E (*pfFSIsExist)(const char *pPath);
    FRESULT_E (*pfFSChMod)(const char *pPath, uint32_t uiMode);
} FS_BASE_S;

/*********************************************************************
 * FUNCTIONS
 */

/**
 *   @Description: 文件系统初始化
 *   @param: NA
 *   @return :FRESULT_E
 */
FRESULT_E fsInstall(void);

/**
 *   @Description: 文件系统逆初始化
 *   @param: pName - 入参，任务名称
 *   @return :FRESULT_E
 */
FRESULT_E fsUninstall(void);

/**
 *   @Description: 打开或创建文件
 *   @param: phFile - 出参，文件描述符
 *   @param: pcPath - 入参，文件路径
 *   @param: ucMode - 入参，文件操作模式
 *   @return :FRESULT_E
 */
FRESULT_E fsOpen(fd_t *phFile, const char* pcPath, uint8_t ucMode);

/**
 *   @Description: 关闭文件
 *   @param: phFile - 入参，文件描述符
 *   @return :FRESULT_E
 */
FRESULT_E fsClose(fd_t *phFile);

/**
 *   @Description: 读取文件内容
 *   @param: phFile - 入参，文件描述符
 *   @param: pBuff - 入参，缓存地址
 *   @param: uiSize - 入参，读取数据大小
 *   @return :FRESULT_E/实际读取到的数据大小
 */
int32_t fsRead(fd_t *phFile, void *pBuff, uint32_t uiSize);

/**
 *   @Description: 读取文件一行
 *   @param: phFile - 入参，文件描述符
 *   @param: pBuff - 入参，缓存地址
 *   @param: uiSize - 入参，读取数据大小
 *   @return :FRESULT_E/实际读取到的数据大小
 */
int32_t fsReadLine(fd_t *phFile, void *pBuff, uint32_t uiSize);

/**
 *   @Description: 向文件写入数据
 *   @param: phFile - 入参，文件描述符
 *   @param: pBuff - 入参，缓存地址
 *   @param: uiSize - 入参，写入的数据大小
 *   @return :FRESULT_E/实际写入的数据大小
 */
int32_t fsWrite(fd_t *phFile, const void *pBuff, uint32_t uiSize);

/**
 *   @Description: 重置/定位文件操作偏移指针
 *   @param: phFile - 入参，文件描述符
 *   @param: iOffset - 入参，相对于基准点的偏移距离(单位:字节)  ( 正数:向后偏移  负数:向前偏移)
 *   @param: ucWhence - 入参，文件偏移指针位置设置的基准点 SEEK_POS_E
 *   @return :FRESULT_E
 */
FRESULT_E fsSeek(fd_t *phFile, int32_t iOffset, uint8_t ucWhence);

/**
 *   @Description: 删除文件
 *   @param: pName - 入参，文件名
 *   @return :FRESULT_E
 */
FRESULT_E fsDelete(const char *pName);

/**
 *   @Description: 获取文件大小
 *   @param: phFile - 入参，文件描述符
 *   @param: puiSize - 出参，文件大小
 *   @return :FRESULT_E
 */
FRESULT_E fsGetSize(fd_t *phFile, uint32_t *puiSize);

/**
 *   @Description: 将缓存的数据写入到文件中
 *   @param  : phFile - 入参，文件描述符
 *   @return : FRESULT_E
 */
FRESULT_E fsFlush(fd_t *phFile);

/**
 *   @Description: 文件重命名
 *   @param: pOldPathle - 入参，原文件名
 *   @param: pNewPath - 入参，新文件名
 *   @return :FRESULT_E
 */
FRESULT_E fsRename(const char *pOldPath, const char *pNewPath);

/**
 *   @Description: 创建目录
 *   @param: pPath - 入参，路径
 *   @return :FRESULT_E
 */
FRESULT_E fsMkDir(const char *pPath);

/**
 *   @Description: 打开目录文件
 *   @param: pcDirPath - 入参，目录路径
 *   @param: pstDir - 出参，目录信息
 *   @return FSDIR_S
 */
FRESULT_E fsDirOpen(const char *pcDirPath, FSDIR_S *pstDir);

/**
 *   @Description: 关闭目录文件
 *   @param: pstDir - 入参，目录句柄
 *   @return :FRESULT_E
 */
FRESULT_E fsDirClose(FSDIR_S *pstDir);

/**
 *   @Description: 读取指定目录下的文件信息，可遍历目录下的所有文件
 *   @param: pstDir - 入参，目录句柄
 *   @param: pstFileInfo - 出参，读出的文件信息
 *   @return :FRESULT_E
 */
FRESULT_E fsDirRead(FSDIR_S *pstDir, FILE_INFO_S *pstFileInfo);

/**
 *   @Description: 获取当前目录
 *   @param: pBuf - 出参，保存当前目录的缓冲区
 *   @param: uiSize - 入参，缓冲区大小
 *   @return :成功返回指向当前目录的指针，和buf 的值一样，错误返回NULL
 */
char *fsGetCwd(char *pBuf, uint32_t uiSize);

/**
 *   @Description: 改变当前工作目录
 *   @param: pPath - 入参，工作目录路径
 *   @return :FRESULT_E
 */
FRESULT_E fsChDir(const char *pPath);

/**
 *   @Description: 文件或目录是存在
 *   @param: pPath - 入参，路径
 *   @return :FRESULT_E, FS_OK表示存在
 */
FRESULT_E fsIsExist(const char *pPath);

/**
 *   @Description: 更改文件属性
 *   @param: pPath - 入参，文件路径
 *   @param: uiMode - 入参，文件属性
 *   @return :FRESULT_E
 */
FRESULT_E fsChMod(const char *pPath, uint32_t uiMode);

#endif      //(SAL_FS == _ENABLE)

#ifdef __cplusplus
}
#endif /* end of __cplusplus */

#endif  // __THREAD_H__

/************************************** The End Of File **************************************/

